# vim:ts=4:sw=4:noet:
""" Memory inspector window """

import wx
from c.remote.simpleobj import *
from c.ui.wxw.widgets.baseframe import BaseFrame

class InspectorObject:
	def __init__(self, value, ptr=None):
		self.value = value
		self.ptr = ptr
		self.expanded = False

	def __repr__(self):
		return "<%s@%s>" % (self.value, self.ptr)

class InspectWindow(BaseFrame):
	def __init__(self, parent, mem, remote, ptr, name="Object"):
		self.mem = mem
		self.r = remote
		self.ptr = ptr
		self.obj = self.r.getObject(ptr)
		cls = self.r.getObject(self.obj.cls)
		clsName = self.r.getObject(cls.data[0]).asString()

		windowName = "Inspect: %s (%d)" % (name, ptr)
		BaseFrame.__init__(self, parent, windowName, size=(300, 350))

		self.tree = wx.TreeCtrl(self)
		root = self.tree.AddRoot("%s @ %d" % (clsName, self.obj.ptr))
		self.tree.SetPyData(root, InspectorObject(clsName, self.obj.ptr))
		
		self.font = wx.Font(10, 
				wx.FONTFAMILY_MODERN,
				wx.FONTSTYLE_NORMAL,
				wx.FONTWEIGHT_NORMAL)
		
		self.objData = {}
		self.AddTreeNodes(root,[InspectorObject("?")])

		self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded, self.tree)
		self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivated, self.tree)
		
		self.Centre()
		self.Show(True)
		
		self.tree.Expand(root)
		self.tree.SetItemFont(root, self.font)
	 

	def objectAsString(self, aobj):
		if not isinstance(aobj,SimpleSmallInt):
			acls = self.r.getObject(aobj.cls)
			aclsName = self.r.getObject(acls.data[0]).asString()
			if aclsName == "Symbol":
				data = "#"
				for d in aobj.data:
					data += chr(d)
				data += " (Symbol)"
				dName = data
				return [InspectorObject(dName),False]
			elif aclsName == "String":
				data = "'"
				for d in aobj.data:
					data += chr(d)
				data += "' (String)"
				dName = data
				return [InspectorObject(dName),False]
			elif aclsName == "Array":
				dName = "%s (%d items)" % (aclsName, aobj.size)
			elif aclsName == "ByteArray":
				dName = "%s (%d bytes)" % (aclsName, aobj.size)
			elif aclsName == "Undefined":
				dName = "nil"
				return [InspectorObject(dName),False]
			else:
				dName = "<%s>" % (aclsName)
			return [InspectorObject(dName, aobj.ptr),True]
		else:
			dName = "%d (SmallInt)" % aobj.val
			return [InspectorObject(dName),False]

	def populateNodeChildren(self, node, obj):
		items = []
		mcls = self.r.getObject(obj.cls)
		mclsName = self.r.getObject(mcls.data[0]).asString()
		if not obj.bin:
			if mclsName=="Dictionary":
				keys = self.r.getObject(obj.data[0]).data
				vals = self.r.getObject(obj.data[1]).data
				for i,d in enumerate(vals):
					aobj = self.r.getObject(d)
					key = self.r.getObject(keys[i]).asString()
					ostr, hasChildren = self.objectAsString(aobj)
					ostr.value = "%s -> %s" % (key, ostr.value)
					if hasChildren:
						items.append([ostr,InspectorObject("?")])
					else:
						items.append(ostr)
			else:
				scls = self.mem.getGlobal(mclsName)
				ivars = []
				if (scls):
					ivars = scls.getAllIvars()
				maxlen = 0
				for iv in ivars:
					if len(iv)>maxlen:
						maxlen = len(iv)
				for i,d in enumerate(obj.data):
					aobj = self.r.getObject(d)
					ostr, hasChildren = self.objectAsString(aobj)
					if i<len(ivars):
						ostr.value = "%s: %s" % (ivars[i].ljust(maxlen+1),ostr.value)
					if hasChildren:
						items.append([ostr,InspectorObject("?")])
					else:
						items.append(ostr)
		else:
			data = ""
			if mclsName=="Symbol":
				data += "#"
			else:
				for d in obj.data:
					data += "%d, " % d
			items.append(InspectorObject(data))
	  
		self.AddTreeNodes(node, items)
      
	def AddTreeNodes(self, parentItem, items):
		for item in items:
			if type(item) == str:
				raise Exception("string!")
			elif isinstance(item, InspectorObject):
				iid = self.tree.AppendItem(parentItem, item.value)
				self.tree.SetPyData(iid, item)
				self.tree.SetItemFont(iid, self.font)
			else:
				newItem = self.tree.AppendItem(parentItem, item[0].value)
				self.tree.SetPyData(newItem, item[0])
				self.tree.SetItemFont(newItem, self.font)
				self.AddTreeNodes(newItem, item[1:])
				
	def OnItemExpanded(self, evt):
		item = evt.GetItem()
		inspobj = self.tree.GetPyData(item)
		if not inspobj.expanded:
			inspobj.expanded = True
			if inspobj.ptr:
				self.tree.DeleteChildren(item)
				self.populateNodeChildren(item, self.r.getObject(inspobj.ptr))
		
	def OnActivated(self, evt):
		item = evt.GetItem()
		inspobj = self.tree.GetPyData(item)
		if inspobj.ptr:
			InspectWindow(self, self.mem, self.r, inspobj.ptr)
